/*
    SpawnSurance - Minecraft Plugin for casualty insurance of inventory contents
    Copyright (C) 2012 Ernest Pazera

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     */
package com.pdg.mcplugin.spawnsurance;

import java.util.logging.Logger;

import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityListener;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

public class SpawnSurance extends JavaPlugin {

	//logger for errors
	private Logger log = Logger.getLogger(Constants.minecraftLoggerName);
	public Logger getLogger(){
		return log;
	}
	
	//plugin manager for attaching eventes
	private PluginManager pluginManager = null;
	public PluginManager getPluginManager(){
		return pluginManager;
	}
	
	//data provider for talking to database
	private DataProvider dataProvider = null;
	public DataProvider getDataProvider(){
		return dataProvider;
	}
	
	//configuration
	private Configuration configuration = null;
	public Configuration getPluginConfiguration(){
		return configuration;
	}
	
	
	//server listener
	private EntityListener entityListener = null;
	private PlayerListener playerListener = null;
	
	//diable event
	@Override
	public void onDisable() {
		//simply send a message to the console
		log.info(Constants.messagePluginDisable);
	}

	//enable event
	@Override
	public void onEnable() {
		//message to console
		log.info(Constants.messagePluginEnabled);
		//grab the plugin
		pluginManager = this.getServer().getPluginManager();
		//create data provider
		dataProvider = new DataProvider(this);
		//create entity listener
		entityListener = new SpawnSuranceEntityListener(this);
		//create player listener
		playerListener = new SpawnSurancePlayerListener(this);
		//create configuration holder
		configuration = new Configuration(this);
		//register events
		pluginManager.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Event.Priority.Normal,this);
		pluginManager.registerEvent(Event.Type.PLAYER_RESPAWN, playerListener, Event.Priority.Normal,this);
	}
	
	public boolean hasUsePermission(Player player){
		//create permission if it doesn't exist
		if(getPluginManager().getPermission(Constants.permissionUse)==null){
			getPluginManager().addPermission(new Permission(Constants.permissionUse, Constants.permissionUseDefault));
		}
		return player.hasPermission(Constants.permissionUse);
	}

	private boolean hasAdminConfigurationPermission(Player player){
		//create permission if it doesn't exist
		if(getPluginManager().getPermission(Constants.permissionAdminConfiguration)==null){
			getPluginManager().addPermission(new Permission(Constants.permissionAdminConfiguration, Constants.permissionAdminConfigurationDefault));
		}
		return player.hasPermission(Constants.permissionAdminConfiguration);
	}

	private boolean hasAdminClaimsPermission(Player player){
		//create permission if it doesn't exist
		if(getPluginManager().getPermission(Constants.permissionAdminClaims)==null){
			getPluginManager().addPermission(new Permission(Constants.permissionAdminClaims, Constants.permissionAdminClaimsDefault));
		}
		return player.hasPermission(Constants.permissionAdminClaims);
	}

	//show the contents of an array to a command sender
	private void showHelpContents(CommandSender theCommandSender, String[] theHelpContents){
		for(String line:theHelpContents){
			theCommandSender.sendMessage(line);
		}
	}
	
	//show general help
	private void showGeneralHelp(CommandSender theCommandSender){
		showHelpContents(theCommandSender,Constants.helpGeneral);
	}
	
	//show help for the "get" function
	private void showGetHelp(CommandSender theCommandSender){
		showHelpContents(theCommandSender,Constants.helpGet);
	}
	
	//show help for the "set" function
	private void showSetHelp(CommandSender theCommandSender){
		showHelpContents(theCommandSender,Constants.helpSet);
	}
	
	//bad command, show this to command sender
	private void showBadCommand(CommandSender theCommandSender){
		theCommandSender.sendMessage(Constants.errorBadCommand);
	}
	
	//show claims for a player name
	private void showClaimsForPlayerName(CommandSender theCommandSender, String thePlayerName){
		//check for current player
		Boolean isCurrentPlayer = false;
		Player player = null;
		if(theCommandSender instanceof Player){
			player = (Player)theCommandSender;
			isCurrentPlayer = (player.getName().equals(thePlayerName));
		}
		//if current player
		if(isCurrentPlayer){
			//require use permission
			if(!hasUsePermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}else{
			//not current player, require claims admin
			if(player!=null){
				if(!hasAdminClaimsPermission(player)){
					theCommandSender.sendMessage(Constants.errorNoPermission);
					return;
				}
			}
		}
		//grab claims and report them
		Integer theClaims = getDataProvider().retrievePlayerClaims(thePlayerName);
		theCommandSender.sendMessage(String.format(Constants.messageClaimsForPlayer, thePlayerName, theClaims));
		
	}
	
	//show current player claims
	private void showGetCurrentPlayerClaims(CommandSender theCommandSender){
		//if this is from a player
		if(theCommandSender instanceof Player){
			//send it along to the claims for playername function
			Player player = (Player)theCommandSender;
			showClaimsForPlayerName(theCommandSender,player.getName());
		}else{
			//error message
			theCommandSender.sendMessage(Constants.errorThereIsNoCurrentPlayer);
		}
	}
	
	//show minimum cost
	private void showGetMinimum(CommandSender theCommandSender){
		//ensure if this is a player that he has the correct permission
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		//show the information
		theCommandSender.sendMessage(String.format(Constants.messageGetMinimum, getPluginConfiguration().getMinimum()));
	}
	
	//show maximum cost
	private void showGetMaximum(CommandSender theCommandSender){
		//ensure if this is a player that he has the correct permission
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		//show the information
		theCommandSender.sendMessage(String.format(Constants.messageGetMaximum, getPluginConfiguration().getMaximum()));
	}
	
	//show acceleration
	private void showGetAcceleration(CommandSender theCommandSender){
		//ensure if this is a player that he has the correct permission
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		//show the information
		theCommandSender.sendMessage(String.format(Constants.messageGetAcceleration, getPluginConfiguration().getAcceleration()));
	}
	
	//show material
	private void showGetMaterial(CommandSender theCommandSender){
		//ensure if this is a player that he has the correct permission
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		//show the information
		theCommandSender.sendMessage(String.format(Constants.messageGetMaterial, getPluginConfiguration().getMaterial().toString()));
	}
	
	//handle commands
	public boolean onCommand(CommandSender theCommandSender, Command theCommand, String theLabel, String[] theArgs){
		//must match "spawnsurance"
		if(theLabel.equalsIgnoreCase(Constants.commandSpawnSurance)){
			//zero arguments
			if(theArgs.length==Constants.argCountZero){
				showGeneralHelp(theCommandSender);
			}else if(theArgs.length==Constants.argCountSingle){//one argument
				if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandHelp) || theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandQuestion)){
					showGeneralHelp(theCommandSender);
					return true;
				}else if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandSet)){
					showSetHelp(theCommandSender);
					return true;
				}else if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandGet)){
					showGetHelp(theCommandSender);
					return true;
				}else if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandCheck)){
					showCurrentPlayerCheck(theCommandSender);
					return true;
				}else{
					showBadCommand(theCommandSender);
					return true;
				}
			}else if(theArgs.length==Constants.argCountDouble){//two arguments
				if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandGet)){
					if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyClaims)){
						showGetCurrentPlayerClaims(theCommandSender);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyAcceleration)){
						showGetAcceleration(theCommandSender);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMinimum)){
						showGetMinimum(theCommandSender);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMaximum)){
						showGetMaximum(theCommandSender);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMaterial)){
						showGetMaterial(theCommandSender);
						return true;
					}else{
						showBadCommand(theCommandSender);
						return true;
					}
				}else{
					showBadCommand(theCommandSender);
					return true;
				}
			}else if(theArgs.length==Constants.argCountTriple){//three arguments
				if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandSet)){
					if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyAcceleration)){
						Integer theValue = Integer.parseInt(theArgs[Constants.argValue1]);
						showSetAcceleration(theCommandSender,theValue);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMinimum)){
						Integer theValue = Integer.parseInt(theArgs[Constants.argValue1]);
						showSetMinimum(theCommandSender,theValue);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMaximum)){
						Integer theValue = Integer.parseInt(theArgs[Constants.argValue1]);
						showSetMaximum(theCommandSender,theValue);
						return true;
					}else if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyMaterial)){
						showSetMaterial(theCommandSender,theArgs[Constants.argValue1]);
						return true;
					}else{
						showBadCommand(theCommandSender);
						return true;
					}
				}else{
					showBadCommand(theCommandSender);
					return true;
				}
			}else{//mor ethan three arguments
				if(theArgs[Constants.argSubcommand].equalsIgnoreCase(Constants.subcommandSet)){
					if(theArgs[Constants.argProperty].equalsIgnoreCase(Constants.commandPropertyClaims)){
						String thePlayerName = theArgs[Constants.argValue1];
						Integer theClaims = Integer.parseInt(theArgs[Constants.argValue2]);
						showSetPlayerClaims(theCommandSender,thePlayerName,theClaims);
						return true;
					}else{
						showBadCommand(theCommandSender);
						return true;
					}
				}else{
					showBadCommand(theCommandSender);
					return true;
				}
			}
		}
		return false;
	}
	
	//check current player's insurance
	private void showCurrentPlayerCheck(CommandSender theCommandSender) {
		//if there is a current player
		if(theCommandSender instanceof Player){
			//determine material and cost of covereage
			Player thePlayer = (Player)theCommandSender;
			Material theMaterial = getPluginConfiguration().getMaterial();
			Integer theCost = getDataProvider().getPlayerCoverageCost(thePlayer);
			Boolean isCovered = getDataProvider().isPlayerCovered(thePlayer);
			//report current cost
			theCommandSender.sendMessage(String.format(Constants.messagePlayerCurrentCost,theCost,theMaterial.toString()));
			//report coverage
			if(isCovered){
				theCommandSender.sendMessage(Constants.messageCovered);
			}else{
				theCommandSender.sendMessage(Constants.messageNotCovered);
			}
		}else{
			//no current player
			theCommandSender.sendMessage(Constants.errorThereIsNoCurrentPlayer);
		}
	}

	//set the players claims
	private void showSetPlayerClaims(CommandSender theCommandSender,
			String thePlayerName, Integer theClaims) {
		//has to either be the console or a playe rwith the correct permission
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminClaimsPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		//set the claims, then show the current number of claims
		if(getDataProvider().setPlayerClaims(thePlayerName, theClaims)){
			showClaimsForPlayerName(theCommandSender,thePlayerName);
		}
	}

	//set the material for configuration
	private void showSetMaterial(CommandSender theCommandSender, String theMaterialName) {
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		Material theMaterial = Material.getMaterial(theMaterialName);
		if(theMaterial==null){
			theCommandSender.sendMessage(Constants.errorInvalidMaterial);
		}else{
			getPluginConfiguration().setMaterial(theMaterial);
			showGetMaterial(theCommandSender);
		}
	}

	//set maximum for configuration
	private void showSetMaximum(CommandSender theCommandSender, Integer theValue) {
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		getPluginConfiguration().setMaximum(theValue);
		showGetMaximum(theCommandSender);
	}

	//set minimum for configuration
	private void showSetMinimum(CommandSender theCommandSender, Integer theValue) {
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		getPluginConfiguration().setMinimum(theValue);
		showGetMinimum(theCommandSender);
	}

	//set acceleration for configuration
	private void showSetAcceleration(CommandSender theCommandSender,
			Integer theValue) {
		if(theCommandSender instanceof Player){
			Player player = (Player)theCommandSender;
			if(!hasAdminConfigurationPermission(player)){
				theCommandSender.sendMessage(Constants.errorNoPermission);
				return;
			}
		}
		getPluginConfiguration().setAcceleration(theValue);
		showGetAcceleration(theCommandSender);
	}

}
